﻿using Entity;
using Repository;
using Sox;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace BusinessIntelligence
{
    public class BusinessIntelligence
    {

        public static Logging log = new Logging();
        public Repository.Repository repo = new Repository.Repository();
        public BusinessIntelligence()
        {

        }

        #region Service Implementation
        public LoginBIResponse LoginProcess(LoginBIRequest request)
        {
            log.EnterMethod(request.Log(), "BI");
            LoginBIResponse response = repo.Login(request);
            log.LeaveMethod(request.Log(), "BI");
            return response;
        }

        public LogoutBIResponse LogoutProcess(LogoutBIRequest request)
        {
            log.EnterMethod(request.Log(), "BI");
            LogoutBIResponse response = repo.Logout(request);
            log.LeaveMethod(request.Log(), "BI");
            return response;
        }

        public GetMsgBIResponse GetMsgProcess(GetMsgBIRequest request)
        {
            log.EnterMethod(request.Log(), "BI");
            if (!IsThereNewMsg(request.TableId))
            {
                GetMsgBIResponse result = new GetMsgBIResponse(212);
                log.LeaveMethod(result.Log(), "BI");
                return result;
            }
            GetMsgBIResponse response = repo.GetMsg(request);
            log.LeaveMethod(request.Log(), "BI");
            return response;
        }

        public CloseGameBIResponse CloseGameProcess(CloseGameBIRequest request)
        {
            log.EnterMethod(request.Log(), "BI");
            if (!IsProperTable(request.TableID, request.UserName))
            {
                CloseGameBIResponse result = new CloseGameBIResponse(213);
                log.LeaveMethod(result.Log(), "BI");
                return result;
            }
            CloseGameBIResponse response = repo.CloseGame(request);
            log.LeaveMethod(request.Log(), "BI");
            return response;
        }

        public GiveUpBIResponse GiveUpProcess(GiveUpBIRequest request)
        {
            log.EnterMethod(request.Log(), "BI");
            if (!IsProperTable(request.TableID, request.UserID))
            {
                GiveUpBIResponse result = new GiveUpBIResponse(213);
                log.LeaveMethod(result.Log(), "BI");
                return result;
            }
            GiveUpBIResponse response = repo.GiveUp(request);
            log.LeaveMethod(request.Log(), "BI");
            return response;
        }

        public JoinGameBIResponse JoinGameProcess(JoinGameBIRequest request)
        {
            log.EnterMethod(request.Log(), "BI");
            if (!IsSameLevel(request.TableID, request.UserName))
            {
                JoinGameBIResponse result = new JoinGameBIResponse(214);
                log.LeaveMethod(result.Log(), "BI");
                return result;
            }
            JoinGameBIResponse response = repo.JoinGame(request);
            log.LeaveMethod(request.Log(), "BI");
            return response;
        }

        public ListGameBIResponse ListGameProcess(ListGameBIRequest request)
        {
            log.EnterMethod(request.Log(), "BI");
            ListGameBIResponse response = repo.ListGame(request);
            log.LeaveMethod(request.Log(), "BI");
            return response;
        }

        public NewGameBIResponse NewGameProcess(NewGameBIRequest request)
        {
            log.EnterMethod(request.Log(), "BI");
            if (IsInGame(request.Username))
            {
                NewGameBIResponse result = new NewGameBIResponse(216);
                log.LeaveMethod(result.Log(), "BI");
                return result;
            }
            NewGameBIResponse response = repo.NewGame(request);
            log.LeaveMethod(request.Log(), "BI");
            return response;
        }

        public PlayerStatsBIResponse PlayerStatsProcess(PlayerStatsBIRequest request)
        {
            log.EnterMethod(request.Log(), "BI");
            PlayerStatsBIResponse response = repo.PlayerStats(request);
            log.LeaveMethod(request.Log(), "BI");
            return response;
        }

        public RegistrationBIResponse RegistrationProcess(RegistrationBIRequest request)
        {
            log.EnterMethod(request.Log(), "BI");
            int code = IsDatasValid(request.Username, request.EmailAddress);
            if (code > 0)
            {
                RegistrationBIResponse result = new RegistrationBIResponse(code);
                log.LeaveMethod(result.Log(), "BI");
                return result;
            }
            RegistrationBIResponse response = repo.Registration(request);
            log.LeaveMethod(request.Log(), "BI");
            return response;
        }

        public SendMsgBIResponse SendMsgProcess(SendMsgBIRequest request)
        {
            log.EnterMethod(request.Log(), "BI");
            if (request.Message == null || !IsMessageValid(request))
            {
                SendMsgBIResponse result = new SendMsgBIResponse(205);
                log.LeaveMethod(result.Log(), "BI");
                return result;
            }
            SendMsgBIResponse response = repo.SendMsg(request);
            log.LeaveMethod(request.Log(), "BI");
            return response;

        }

        public StepBIResponse StepProcess(StepBIRequest request)
        {
            log.EnterMethod(request.Log(), "BI");
            StepBIResponse response = new StepBIResponse();
            bool valid = IsStepValid(request, ref response);
            if (!valid)
            {
                StepBIResponse result = new StepBIResponse(206);
                log.LeaveMethod(result.Log(), "BI");
                return result;
            }
            response = repo.Step(request,response);
            log.LeaveMethod(request.Log(), "BI");
            return response;
        }

        #endregion

        #region Checking datas
        private bool IsStepValid(StepBIRequest request, ref StepBIResponse response)
        {
            if (Turn(request))
            {
                int fromX = -1;
                int toX = -1;
                int fromY = -1;
                int toY = -1;
                fromX = GetColumn(request.StepFrom.X);
                toX = GetColumn(request.StepTo.X);
                fromY = GetRow(request.StepFrom.Y);
                toY = GetRow(request.StepTo.Y);

                //FirstPlayer: true ==> ződ

                if (request.FirstPlayer == true)
                {
                    if (IsKing(request))
                    {
                        if (Math.Abs(fromX - toX) == 1 && Math.Abs(fromX - toX) != 0 &&
                            (Math.Abs(fromY - toY) == 1 && (toY - 1) == fromY))
                        {
                            bool isvalid = !IsReserved(request);
                            response.Kill = false;
                            return isvalid ? true : false;
                        }
                        else if (Math.Abs(fromX - toX) == 2 && Math.Abs(fromX - toX) != 0 &&
                            (Math.Abs(fromY - toY) == 2 && (toY - 2) == fromY))
                        {
                            int adjX = 0;
                            int adjY = 0;
                            if (toX - fromX < 0)
                            {
                                adjX = 1;
                            }
                            else
                            {
                                adjX = -1;
                            }
                            if (toY - fromY < 0)
                            {
                                adjY = 1;
                            }
                            else
                            {
                                adjY = -1;
                            }
                            Point ad = new Point();
                            ad.X = GetColumn(toX + adjX);
                            ad.Y = GetRow(toY + adjY);
                            StepBIRequest check = new StepBIRequest(request);
                            check.StepTo = ad;
                            bool isvalidFirst = IsReserved(check);
                            bool isEnemy = IsEnemy(check, true);
                            bool isvalidSecond = !IsReserved(request);
                            if (isvalidFirst && isEnemy && isvalidSecond)
                            {
                                bool isKill = IsKill(request, check);
                                if (isKill)
                                {
                                    response.Kill = true;
                                    response.X = ad.X;
                                    response.Y = ad.Y;
                                    return true;
                                }
                                else
                                {
                                    response.Kill = false;
                                    return false;
                                }
                            }
                            else if (isvalidFirst && !isEnemy && isvalidSecond)
                            {
                                response.Kill = false;
                                return true;
                            }
                            response.Kill = false;
                            return false;
                        }
                    }
                    else
                    {
                        if (Math.Abs(fromX - toX) == 1 && Math.Abs(fromX - toX) != 0 &&
                            ((fromY - toY) == 1))
                        {
                            bool isvalid = !IsReserved(request);
                            response.Kill = false;
                            return isvalid ? true : false;
                        }
                        else if (Math.Abs(fromX - toX) == 2 && Math.Abs(fromX - toX) != 0 &&
                            ((fromY - toY) == 2))
                        {
                            int adjX = 0;
                            int adjY = 0;
                            if (toX - fromX < 0)
                            {
                                adjX = 1;
                            }
                            else
                            {
                                adjX = -1;
                            }
                            if (toY - fromY < 0)
                            {
                                adjY = 1;
                            }
                            else
                            {
                                adjY = -1;
                            }
                            Point ad = new Point();
                            ad.X = GetColumn(toX + adjX);
                            ad.Y = GetRow(toY + adjY);
                            StepBIRequest check = new StepBIRequest(request);
                            check.StepTo = ad;
                            bool isvalidFirst = IsReserved(check);
                            bool isEnemy = IsEnemy(check, true);
                            bool isvalidSecond = !IsReserved(request);
                            if (isvalidFirst && isEnemy && isvalidSecond)
                            {
                                bool isKill = IsKill(request, check);
                                if (isKill)
                                {
                                    response.Kill = true;
                                    response.X = ad.X;
                                    response.Y = ad.Y;
                                    return true;
                                }
                                else
                                {
                                    response.Kill = false;
                                    return false;
                                }
                            }
                            response.Kill = false;
                            return false;
                        }
                    }
                }
                else
                {
                    if (IsKing(request))
                    {
                        if (Math.Abs(fromX - toX) < 3 && Math.Abs(fromX - toX) != 0 &&
                            (Math.Abs(fromY - toY) == 1 && (toY + 1) == fromY))
                        {
                            bool isvalid = !IsReserved(request);
                            response.Kill = false;
                            return isvalid ? true : false;
                        }
                        else if (Math.Abs(fromX - toX) < 3 && Math.Abs(fromX - toX) != 0 &&
                            (Math.Abs(fromY - toY) == 2 && (toY + 2) == fromY))
                        {
                            int adjX = 0;
                            int adjY = 0;
                            if (toX - fromX < 0)
                            {
                                adjX = 1;
                            }
                            else
                            {
                                adjX = -1;
                            }
                            if (toY - fromY < 0)
                            {
                                adjY = 1;
                            }
                            else
                            {
                                adjY = -1;
                            }
                            Point ad = new Point();
                            ad.X = GetColumn(toX + adjX);
                            ad.Y = GetRow(toY + adjY);
                            StepBIRequest check = new StepBIRequest(request);
                            check.StepTo = ad;
                            bool isvalidFirst = IsReserved(check);
                            bool isEnemy = IsEnemy(check, false);
                            bool isvalidSecond = !IsReserved(request);
                            if (isvalidFirst && isEnemy && isvalidSecond)
                            {
                                bool isKill = IsKill(request, check);
                                if (isKill)
                                {
                                    response.Kill = true;
                                    response.X = ad.X;
                                    response.Y = ad.Y;
                                    return true;
                                }
                                else
                                {
                                    response.Kill = false;
                                    return false;
                                }
                            }
                            else if (isvalidFirst && !isEnemy && isvalidSecond)
                            {
                                response.Kill = false;
                                return true;
                            }
                            response.Kill = false;
                            return false;
                        }
                    }
                    else
                    {
                        if (Math.Abs(fromX - toX) == 1 && Math.Abs(fromX - toX) != 0 &&
                            ((fromY - toY) == -1))
                        {
                            bool isvalid = !IsReserved(request);
                            return isvalid ? true : false;
                        }
                        else if (Math.Abs(fromX - toX) == 2 && Math.Abs(fromX - toX) != 0 &&
                            ((fromY - toY) == -2))
                        {
                            int adjX = 0;
                            int adjY = 0;
                            if (toX - fromX < 0)
                            {
                                adjX = 1;
                            }
                            else
                            {
                                adjX = -1;
                            }
                            if (toY - fromY < 0)
                            {
                                adjY = 1;
                            }
                            else
                            {
                                adjY = -1;
                            }
                            Point ad = new Point();
                            ad.X = GetColumn(toX + adjX);
                            ad.Y = GetRow(toY + adjY);
                            StepBIRequest check = new StepBIRequest(request);
                            check.StepTo = ad;
                            bool isvalidFirst = IsReserved(check);
                            bool isEnemy = IsEnemy(check, false);
                            bool isvalidSecond = !IsReserved(request);
                            if (isvalidFirst && isEnemy && isvalidSecond)
                            {
                                bool isKill = IsKill(request, check);
                                if (isKill)
                                {
                                    response.Kill = true;
                                    response.X = ad.X;
                                    response.Y = ad.Y;
                                    return true;
                                }
                                else
                                {
                                    response.Kill = false;
                                    return false;
                                }
                            }
                            else if (isvalidFirst && !isEnemy && isvalidSecond)
                            {
                                response.Kill = false;
                                return false;
                            }
                        }
                    }
                }
            }
            response.Kill = false;
            return false;

        }

        private bool IsInGame(string request)
        {
            return repo.IsInGame(request);
        }

        private bool Turn(StepBIRequest request)
        {
            return repo.Turn(request);
        }

        private bool IsKill(StepBIRequest request, StepBIRequest check)
        {
            return repo.IsKill(request, check);
        }

        private bool IsKing(StepBIRequest request)
        {
            return repo.IsKing(request);
        }

        private bool IsEnemy(StepBIRequest request, bool color)
        {
            return repo.IsEnemy(request, color);
        }

        private bool IsReserved(StepBIRequest request)
        {
            return repo.IsReserved(request);
        }

        private int GetRow(string request)
        {
            int fromY = 0;

            if (request == "1")
                fromY = 0;
            else if (request == "2")
                fromY = 1;
            else if (request == "3")
                fromY = 2;
            else if (request == "4")
                fromY = 3;
            else if (request == "5")
                fromY = 4;
            else if (request == "6")
                fromY = 5;
            else if (request == "7")
                fromY = 6;
            else if (request == "8")
                fromY = 7;

            return fromY;
        }

        private int GetColumn(string request)
        {
            int fromX = 0;

            if (request == "A")
                fromX = 0;
            else if (request == "B")
                fromX = 1;
            else if (request == "C")
                fromX = 2;
            else if (request == "D")
                fromX = 3;
            else if (request == "E")
                fromX = 4;
            else if (request == "F")
                fromX = 5;
            else if (request == "G")
                fromX = 6;
            else if (request == "H")
                fromX = 7;

            return fromX;
        }

        private string GetRow(int request)
        {
            string fromY = "0";

            if (request == 0)
                fromY = "1";
            else if (request == 1)
                fromY = "2";
            else if (request == 2)
                fromY = "3";
            else if (request == 3)
                fromY = "4";
            else if (request == 4)
                fromY = "5";
            else if (request == 5)
                fromY = "6";
            else if (request == 6)
                fromY = "7";
            else if (request == 7)
                fromY = "8";

            return fromY;
        }

        private string GetColumn(int request)
        {
            string fromX = "Z";

            if (request == 0)
                fromX = "A";
            else if (request == 1)
                fromX = "B";
            else if (request == 2)
                fromX = "C";
            else if (request == 3)
                fromX = "D";
            else if (request == 4)
                fromX = "E";
            else if (request == 5)
                fromX = "F";
            else if (request == 6)
                fromX = "G";
            else if (request == 7)
                fromX = "H";

            return fromX;
        }

        private bool IsMessageValid(SendMsgBIRequest request)
        {
            Regex regex = new Regex(@"[A-Za-z0-9\-\.\?\!\,\:]*");
            Match match = regex.Match(request.Message);
            return match.Success ? true : false;
        }

        public bool IsLogged(string Username)
        {
            return repo.IsLogged(Username);
        }

        public bool IsGameAlive(string ID)
        {
            return repo.IsGameAlive(ID);
        }

        private bool IsThereNewMsg(string TableID)
        {
            return repo.IsThereNewMsg(TableID);
        }

        private bool IsProperTable(string TableID, string Username)
        {
            return repo.IsProperTable(TableID, Username);
        }

        private bool IsSameLevel(string TableID, string Username)
        {
            return repo.IsSameLevel(TableID, Username);
        }

        private int IsDatasValid(string Username, string Email)
        {
            if (Username == "Guest")
            {
                return 0;
            }
            string usernameValidation = @"^(?=[a-zA-Z0-9])[-\w.]{0,23}([a-zA-Z0-9\d]|(?<![-.]))$";
            if (Regex.IsMatch(Username, usernameValidation, RegexOptions.IgnoreCase))
            {
                bool usernameValid = repo.IsDatasValid(Username);
                if (!usernameValid)
                {
                    return 200;
                }
            }
            else
            {
                return 217;
            }
            
            string pattern = @"\A(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\Z";
            if (!Regex.IsMatch(Email, pattern, RegexOptions.IgnoreCase))
            {
                return 203;
            }
            return 0;
        }
        #endregion
    }
}
